package nl.boelen.game.server;

import nl.boelen.game.server.connection.ServerPacketHandler;
import nl.boelen.game.server.connection.ServerTCPReceiver;
import nl.boelen.game.server.connection.ServerTCPSender;
import nl.boelen.game.server.connection.ServerUDP;
import nl.boelen.game.server.entity.Players;
import nl.boelen.game.server.gui.ServerGUI;

public class Server implements Runnable {

    private static final double FRAMELIMIT = 60D;
    private static final double NANO = 1000000000D;

    private boolean running = false;

    private Thread serverThread;
    public ServerGUI serverGUI;

    public Players players;

    private static long startTime;

    public Server() {
    }

    public void start() {
        running = true;
        players = new Players(this);
        serverGUI = new ServerGUI(this);
        
        ServerTCPSender TCPSender = new ServerTCPSender();
        ServerPacketHandler packetHandler = new ServerPacketHandler(serverGUI, players, TCPSender);
        ServerUDP UDP = new ServerUDP(packetHandler);
        ServerTCPReceiver TCPReceiver = new ServerTCPReceiver(packetHandler);

        players.setConnections(UDP, TCPSender);

        if (UDP.hasSocket) {
            UDP.start();
            TCPReceiver.start();

            serverGUI.GUILog("Started Server");

            serverThread = new Thread(this);
            serverThread.run();
        }
    }

    public void stop() {
        running = false;
    }

    public void init() {
    }

    public void run() {
        long lastTime = System.nanoTime();
        long clock = System.currentTimeMillis();
        int ticks = 0;
        double nsPerTick = NANO / FRAMELIMIT;
        double nsUpdateCounter = 0;

        init();

        while (running) {
            long now = System.nanoTime();
            nsUpdateCounter += (now - lastTime) / nsPerTick;
            lastTime = now;

            // Limit the overload of rendering
            while (nsUpdateCounter >= 1) {
                ticks++;
                tick();
                nsUpdateCounter -= 1;
            }

            limitUsage();

            if (System.currentTimeMillis() - clock > 1000) {
                clock += 1000;
                serverGUI.setGUITitle(getRunningTime() + " || " + ticks + " ticks");
                ticks = 0;
            }
        }
    }

    public String getRunningTime() {
        long time = (System.currentTimeMillis() - startTime);
        int seconds = (int) (time / 1000);
        int h = (seconds / (60 * 60));
        seconds -= (h * (60 * 60));
        int m = (seconds / 60);
        seconds -= (m * 60);
        int s = seconds;

        return "[" + h + ":" + (m >= 10 ? m : "0" + m) + ":" + (s >= 10 ? s : "0" + s) + "]";
    }

    private void limitUsage() {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void tick() {
        serverGUI.tick();
        players.tick();
    }

    public static void main(String args[]) {
        startTime = System.currentTimeMillis();
        new Server().start();
    }
}